import spinal_loongarch_core132.RegFile

import spinal.core._
import spinal.sim._
import spinal.core.sim._

import scala.util.Random

//RegFile's testbench
object RegFileSim {
    val nports = 2
    val awidth = 5
    val dwidth = 32
    val nentry = 1<<awidth
    val amask:Int = (1<<awidth) - 1
    val dmask:Long = (1L << dwidth) - 1L
    def getNextAddr() = Random.nextInt() & amask
    def getNextData() = Random.nextLong() & dmask
    def main(args: Array[String]) {
        SimConfig.withWave.doSim(new RegFile(nports)){dut =>
            //Fork a process to generate the reset and the clock on the dut
            dut.clockDomain.forkStimulus(period = 10)

            var value = new Array[Long](nentry)
            var valid = new Array[Boolean](nentry)
            value(0) = 0L
            valid(0) = true
            for(idx <- 0 to 99){
                val raddr = for(i <- 0 until nports) yield getNextAddr()
                for(i <- 0 until nports){
                    dut.io.r(i).addr #= raddr(i)
                }
                sleep(1)
                for(i <- 0 until nports if valid(raddr(i))){
                    if(dut.io.r(i).data.toLong != value(raddr(i))){
                        println(raddr(i) + ":"+dut.io.r(i).data.toLong + "should equals" + value(raddr(i)))
                    }
                    assert(dut.io.r(i).data.toLong == value(raddr(i)))
                }
                val write = Random.nextBoolean()
                dut.io.w.en #= write
                if (write){
                    val waddr = getNextAddr()
                    val wdata = getNextData()
                    dut.io.w.addr #= waddr
                    dut.io.w.data #= wdata
                    if(waddr != 0){
                        valid(waddr) = true
                        value(waddr) = wdata
                    }
                }
                //Wait a rising edge on the clock
                dut.clockDomain.waitRisingEdge()
            }
        }
    }
}
